﻿
using CSharpLibs.Annotations;
using System.Collections;
using System.Collections.Generic;

#pragma warning disable 0169
#pragma warning disable 0649

namespace System
{
	/*
	 * 
	 * Arrays are supposed to implicitly implement IList<T>, ICollection<T>, and IEnumerable<T> (which requires an implicit implementation 
	 * of a IEnumerator<T> for the array contents as well.
	 * 
	 * WE DO NOT IMPLEMENT THIS YET IN THE FRONT-END.
	 */ 

	[Builtin]
	public abstract class Array : Object, ICloneable
	{
		internal Array()
		{
		}

		public object Clone()
		{
			return base.MemberwiseClone();
		}

		public int Length 
		{
			[BuiltinMethod, BuiltinSemantics("array_getlength"), DoNotClearCollectionPosition]
			get { return -1; } 
		}

		public static int BinarySearch<T>(T[] array, T value)
		{ return BinarySearch(array, 0, array.Length, value); }

		public static int BinarySearch<T>(T[] array, T value, Comparer<T> comparer)
		{ return BinarySearch(array, 0, array.Length, value, comparer); }

		public static int BinarySearch<T>(T[] array, int index, int length, T value)
		{
			int low = index;
			int hi = (index + length) - 1;

			while(low <= hi)
			{
				int num6;
				int num5 = GetMedian(low, hi);

				num6 = Comparer<T>.DefaultCompare(array[num5], value);

				if(num6 == 0)
					return num5;
				if(num6 < 0)
					low = num5 + 1;
				else
					hi = num5 - 1;
			}

			return ~low;
		}

		public static int BinarySearch<T>(T[] array, int index, int length, T value, Comparer<T> comparer)
		{
			int low = index;
			int hi = (index + length) - 1;

			while(low <= hi)
			{
				int num6;
				int num5 = GetMedian(low, hi);
				
				num6 = comparer.Compare(array[num5], value);

				if(num6 == 0)
					return num5;
				if(num6 < 0)
					low = num5 + 1;
				else
					hi = num5 - 1;
			}

			return ~low;
		}

		private static int GetMedian(int low, int hi)
		{
			return (low + ((hi - low) >> 1));
		}

		public static void Copy<T>(T[] sourceArray, T[] destinationArray, int length)
		{ Copy<T>(sourceArray, 0, destinationArray, 0, length); }

		public static void Copy<T>(T[] sourceArray, int sourceIndex, T[] destinationArray, int destinationIndex, int length)
		{
			for(int i = 0; i < length; ++i)
				destinationArray[destinationIndex + i] = sourceArray[sourceIndex + i];
		}
		
		[BuiltinMethod, BuiltinSemantics("array_clear")]
		public static void Clear(Array array, int index, int length)
		{ ;}

		public static bool Exists<T>(T[] array, Predicate<T> match)
		{ return (FindIndex<T>(array, match) != -1); }

		public static T Find<T>(T[] array, Predicate<T> match)
		{
			for(int i = 0; i < array.Length; i++)
			{
				if(match(array[i]))
					return array[i];
			}

			return default(T);
		}

		public static int FindIndex<T>(T[] array, Predicate<T> match)
		{ return FindIndex<T>(array, 0, array.Length, match); }

		public static int FindIndex<T>(T[] array, int startIndex, Predicate<T> match)
		{ return FindIndex<T>(array, startIndex, array.Length - startIndex, match); }

		public static int FindIndex<T>(T[] array, int startIndex, int count, Predicate<T> match)
		{
			int num = startIndex + count;
			for(int i = startIndex; i < num; i++)
			{
				if(match(array[i]))
					return i;
			}
			return -1;
		}

		public static T FindLast<T>(T[] array, Predicate<T> match)
		{
			for(int i = array.Length - 1; i >= 0; i--)
			{
				if(match(array[i]))
					return array[i];
			}

			return default(T);
		}

		public static int FindLastIndex<T>(T[] array, Predicate<T> match)
		{ return FindLastIndex<T>(array, array.Length - 1, array.Length, match); }

		public static int FindLastIndex<T>(T[] array, int startIndex, Predicate<T> match)
		{ return FindLastIndex<T>(array, startIndex, startIndex + 1, match); }

		public static int FindLastIndex<T>(T[] array, int startIndex, int count, Predicate<T> match)
		{
			int num = startIndex - count;
			for(int i = startIndex; i > num; i--)
			{
				if(match(array[i]))
					return i;
			}
			return -1;
		}

		public static void ForEach<T>(T[] array, Action<T> action)
		{
			for(int i = 0; i < array.Length; i++)
				action(array[i]);
		}

		public static int IndexOf<T>(T[] array, T value)
		{
			for(int i = 0; i < array.Length; ++i)
			{
				if(EqualityComparer<T>.DefaultEquals(value, array[i]))
					return i;
			}

			return -1;
		}

		public static int IndexOf<T>(T[] array, T value, int startIndex)
		{
			for(int i = startIndex; i < array.Length; ++i)
			{
				if(EqualityComparer<T>.DefaultEquals(value, array[i]))
					return i;
			}

			return -1;
		}

		public static int IndexOf<T>(T[] array, T value, int startIndex, int count)
		{
			for(int i = startIndex; i < startIndex + count; ++i)
			{
				if(EqualityComparer<T>.DefaultEquals(value, array[i]))
					return i;
			}

			return -1;
		}

		public static int LastIndexOf<T>(T[] array, T value)
		{ return LastIndexOf<T>(array, value, array.Length - 1, array.Length); }

		public static int LastIndexOf<T>(T[] array, T value, int startIndex)
		{ return LastIndexOf<T>(array, value, startIndex, (array.Length == 0) ? 0 : (startIndex + 1)); }

		public static int LastIndexOf<T>(T[] array, T value, int startIndex, int count)
		{
			if(array.Length == 0)
				return -1;

			int num = (startIndex - count) + 1;
			for(int i = startIndex; i >= num; i--)
			{
				if(EqualityComparer<T>.DefaultEquals(array[i], value))
					return i;
			}

			return -1;
		}

		public static void Resize<T>(ref T[] array, int newSize)
		{
			T[] sourceArray = array;
			if(sourceArray == null)
				array = new T[newSize];
			else if(sourceArray.Length != newSize)
			{
				T[] destinationArray = new T[newSize];
				Array.Copy<T>(sourceArray, 0, destinationArray, 0, (sourceArray.Length > newSize) ? newSize : sourceArray.Length);
				array = destinationArray;
			}
			else
			{ ;}
		}

		public static void Reverse<T>(T[] array)
		{ Reverse(array, 0, array.Length); }

		public static void Reverse<T>(T[] array, int index, int length)
		{
			int num = index;
			int num2 = (index + length) - 1;
			while(num < num2)
			{
				T obj2 = array[num];
				array[num] = array[num2];
				array[num2] = obj2;
				num++;
				num2--;
			}
		}

		public static void Sort<T>(T[] array)
		{
			int[] order = ShellSortIndex<T>(array, 0, array.Length);
			SortContents<T>(array, order);
		}

		public static void Sort<T>(T[] array, Comparer<T> comparer)
		{
			int[] order = ShellSortIndex<T>(array, 0, array.Length, comparer);
			SortContents<T>(array, order);
		}

		public static void Sort<T>(T[] array, int index, int length)
		{
			int[] order = ShellSortIndex<T>(array, index, length);
			SortContents<T>(array, order);
		}

		public static void Sort<T>(T[] array, int index, int length, Comparer<T> comparer)
		{
			int[] order = ShellSortIndex<T>(array, index, length, comparer);
			SortContents<T>(array, order);
		}

		public static bool TrueForAll<T>(T[] array, Predicate<T> match)
		{
			for(int i = 0; i < array.Length; i++)
			{
				if(!match(array[i]))
				{
					return false;
				}
			}
			return true;
		}

		//////////////////////////////
		//Sort herlpers

		internal static int[] ShellSortIndex<T>(T[] array, int index, int length)
		{
			int[] data = new int[array.Length];
			int len = data.Length;
			for(int i = 0; i < len; ++i)
				data[i] = i;

			int inner, outer, temp;

			//find initial value of h 
			int h = 1;
			while(h <= length / 3)
				h = h * 3 + 1; // (1, 4, 13, 40, 121, ...) 

			while(h > 0) // decreasing h, until h=1 
			{
				// h-sort the file 
				for(outer = h; outer < len; outer++)
				{
					inner = outer;
					temp = data[inner + index];

					// one subpass (eg 0, 4, 8) 
					while(inner > h - 1 && Comparer<T>.DefaultCompare(array[data[(inner + index) - h]], array[temp]) != -1)
					{
						data[inner + index] = data[(inner + index) - h];
						inner -= h;
					}
					data[(inner + index)] = temp;
				}
				h = (h - 1) / 3; // decrease h 
			}

			return data;
		}

		internal static int[] ShellSortIndex<T>(T[] array, int index, int length, Comparer<T> compare)
		{
			int[] data = new int[array.Length];
			int len = data.Length;
			for(int i = 0; i < len; ++i)
				data[i] = i;

			int inner, outer, temp;

			//find initial value of h 
			int h = 1;
			while(h <= length / 3)
				h = h * 3 + 1; // (1, 4, 13, 40, 121, ...) 

			while(h > 0) // decreasing h, until h=1 
			{
				// h-sort the file 
				for(outer = h; outer < len; outer++)
				{
					inner = outer;
					temp = data[inner + index];

					// one subpass (eg 0, 4, 8) 
					while(inner > h - 1 && Comparer<T>.DefaultCompare(array[data[(inner + index) - h]], array[temp]) != -1)
					{
						data[inner + index] = data[(inner + index) - h];
						inner -= h;
					}
					data[(inner + index)] = temp;
				}
				h = (h - 1) / 3; // decrease h 
			}

			return data;
		}

		[BuiltinMethod, BuiltinSemantics("array_sort_on")]
		internal static void SortContents<T>(T[] contents, int[] order)
		{ ;}
	}
}

#pragma warning restore 0649
#pragma warning restore 0169
